﻿using System;
using System.Linq;
using System.Text;
using System.Timers;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Navigation;
using System.Collections.Generic;
using System.Windows.Media.Imaging;

using Cratos.Desktop;
using Cratos.Tools.General;
using Cratos.Tools.DataObject;

namespace Cratos.Generator
{
	/// <summary>
	/// Application Shell class
	/// </summary>
	public partial class ApplicationShell : Window
	{
		#region Class Delegate declarations
		private delegate void UpdateServerStatus(string serverStatus);
		#endregion

		#region Custom Routed Commands
		/// <summary>
		/// New Project custom command
		/// </summary>
		public static RoutedCommand NewProjectCommand = new RoutedCommand();

		/// <summary>
		/// Open Project custom command
		/// </summary>
		public static RoutedCommand OpenProjectCommand = new RoutedCommand();
		#endregion

		#region Class Constant declarations
		#endregion

		#region Class Event declarations
		#endregion

		#region Class Variable declarations
		private Timer m_ServerTimer;
		#endregion

		#region Class Constructors & Destructors
		/// <summary>
		/// Class Constructor
		/// </summary>
		public ApplicationShell()
		{
			// Initialize the relevant components
			InitializeComponent();

			// Create and setup a new Application Presenter
			this.DataContext = new ApplicationPresenter(this);
		}
		#endregion

		#region Class Properties
		/// <summary>
		/// Application Presenter
		/// </summary>
		public ApplicationPresenter Presenter
		{
			get { return (this.DataContext as ApplicationPresenter); }
		}
		#endregion

		#region Class Methods
		/// <summary>
		/// Add a new Tab
		/// </summary>
		/// <typeparam name="T">View</typeparam>
		/// <param name="currentPresenter">Presenter</param>
		public void AddTab<T>(MVPPresenter<T> currentPresenter)
		{
			// Declare the required variables
			TabItem newTab = null;
			Binding headerBinding;

			// Determine if we have the Tab open already
			foreach (TabItem currentTabItem in this.m_MainTabControl.Items)
			{
				if (currentTabItem.DataContext.Equals(currentPresenter))
				{
					// Remove and save the existing tab
					this.m_MainTabControl.Items.Remove(currentTabItem);
					newTab = currentTabItem;
					break;
				}
			}

			// Create and setup the new Tab if required
			if (newTab == null)
			{
				// Create and setup the new Tab
				newTab = new TabItem();

				// Update the relevant Binding
				headerBinding = new Binding(currentPresenter.Header);
				headerBinding = new Binding("Header");
				BindingOperations.SetBinding(newTab, TabItem.HeaderProperty, headerBinding);

				// Update the Tab Data Context and View
				newTab.DataContext = currentPresenter;
				newTab.Content     = currentPresenter.View;
			}

			// Insert the new Tab at the beginning and set the focus to it
			this.m_MainTabControl.Items.Insert(0, newTab);
			newTab.Focus();

			// return to calling method
			return;
		}

		/// <summary>
		/// Remove an existing Tab
		/// </summary>
		/// <typeparam name="T">View</typeparam>
		/// <param name="currentPresenter">Presenter</param>
		public void RemoveTab<T>(MVPPresenter<T> currentPresenter)
		{
			// Declare the required variables

			// Search for the relevant Tab
			foreach (TabItem currentTabItem in this.m_MainTabControl.Items)
			{
				if (currentTabItem.DataContext.Equals(currentPresenter))
				{
					// Remove the Tab
					this.m_MainTabControl.Items.Remove(currentTabItem);
					break;
				}
			}

			// Return to calling method
			return;
		}

		/// <summary>
		/// Close all Tabs
		/// </summary>
		public void CloseAllTabs()
		{
			// Declare the required variables

			// Remove all Tabs
			this.m_MainTabControl.Items.Clear();

			// Return to calling method
			return;
		}
		#endregion

		#region Window Event Handlers
		private void OnWindowLoaded(object sender, RoutedEventArgs e)
		{
			// Declare the required variables

			// Subscribe to the relevant events
			CWcfService.WebServiceOnline  += new ServerStateEventHandler(this.OnServerOnline);
			CWcfService.WebServiceOffline += new ServerStateEventHandler(this.OnServerOffline);

			// Create, setup and activate the Server Timer
			this.m_ServerTimer          = new Timer(1000);
			this.m_ServerTimer.Elapsed += new ElapsedEventHandler(this.OnServerTimerElapsed);
			this.m_ServerTimer.Enabled  = true;

			// Return to calling method
			return;
		}

		private void OnServerTimerElapsed(object sender, ElapsedEventArgs e)
		{
			// Declare the required variables

			// Disable the Timer
			this.m_ServerTimer.Enabled = false;

			// Ping the Raptor Service if necessary
			if (DOCratosGlobal.EntityAccessMethod == CratosEntityAccessType.CratosProxy)
			{
				// Update the WCF Service
				CWcfService.Url = DOCratosGlobal.WcfServiceAddress;

				// Ping the WCF Service
				if (!CWcfService.Ping()) { this.m_ServerTimer.Enabled = true; }
			}

			// Return to calling method
			return;
		}

		#region Application Commands
		private void OnCloseCommand(object sender, ExecutedRoutedEventArgs e)
		{
			// Declare the required variables

			// Close the application
			this.Close();

			// Return to calling method
			return;
		}

		private void OnCloseCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			// Declare the required variables

			// Set the relevant command
			e.CanExecute = true;

			// Return to calling method
			return;
		}

		private void OnNewProjectCommand(object sender, ExecutedRoutedEventArgs e)
		{
			// Declare the required variables

			// Open the Logon View
			(this.DataContext as ApplicationPresenter).NewProject();

			// Return to calling method
			return;
		}

		private void OnNewProjectCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			// Declare the required variables

			// Set the default action
			e.CanExecute = true;

			// Return to calling method
			return;
		}

		private void OnOpenProjectCommand(object sender, ExecutedRoutedEventArgs e)
		{
			// Declare the required variables
			OpenProjectView openProjectView;

			// Create and setup the required object(s)
			openProjectView           = new OpenProjectView();
			openProjectView.Presenter = new OpenProjectPresenter(this.Presenter, openProjectView);

			// Display the Dialog
			openProjectView.ShowDialog();

			// Return to calling method
			return;
		}

		private void OnOpenProjectCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			// Declare the required variables

			// Set the default action
			e.CanExecute = true;

			// Return to calling method
			return;
		}
		#endregion
		#endregion

		#region Custom Event handlers
		private void OnServerOnline()
		{
			// Declare the required variables

			// Update the Status bar
			this.m_Status.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
																					 new UpdateServerStatus(this.UpdateCratosServiceStatus), "Online");

			// Return to calling method
			return;
		}

		private void OnServerOffline()
		{
			// Declare the required variables

			// Update the Status bar
			this.m_Status.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
																					 new UpdateServerStatus(this.UpdateCratosServiceStatus), "Offline");

			// Restart the Timer
			this.m_ServerTimer.Interval = 5000;
			this.m_ServerTimer.Enabled = true;

			// Return to calling method
			return;
		}
		#endregion

		#region Class Support Methods
		private void UpdateCratosServiceStatus(string raptorStatus)
		{
			// Declare the required variables

			// Handle the incoming status
			if (raptorStatus == "Offline")
			{
				// Update the Status bar
				this.m_StatusImage.Source = new BitmapImage(new Uri("pack://application:,,,/Images/disconnect.png"));
				this.m_Status.ToolTip     = "Server Offline";

				// Enable the Timer
				this.m_ServerTimer.Enabled = true;
			}
			else
			{
				// Update the Status bar
				this.m_StatusImage.Source = new BitmapImage(new Uri("pack://application:,,,/Images/connect.png"));
				this.m_Status.ToolTip     = "Server Online";
			}

			// Return to calling method
			return;
		}
		#endregion
	}
}
